/**
 * Copyright (c) 2010-2011 Pierre Labatut
 *
 * This file is part of Space-Chronicles project.
 *
 * Space-Chronicles is free software: you can redistribute it and/or modify it
 * under the terms of its license which may be found in the accompanying
 * LICENSE file or <http://code.google.com/p/space-chronicles/>.
 */
package space.app.common;

import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.jnlp.BasicService;
import javax.jnlp.ServiceManager;
import javax.jnlp.UnavailableServiceException;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import space.debug.DbgError;

/**
 *
 * @author Pierre
 */
public abstract class ServerFrame<Message> extends JFrame {

    protected final  Application<Message> application;
    private final ServerTray tray;

    
    /**
     * Application icon resources, immutable list
     */
    private final Icon networkIdle = loadImage("network-idle-16.png");
    private final Icon networkOffline = loadImage("network-offline-16.png");
    private final Icon networkError = loadImage("network-error-16.png");
    private final Icon networkRecieve = loadImage("network-transmit-receive-16.png");

    abstract protected JLabel getStatusLablel();
    public final Action showAction = new AbstractAction("Show") {

        public void actionPerformed(ActionEvent e) {
            setVisible(true);
            setExtendedState(getExtendedState() & (~JFrame.ICONIFIED));
        }
    };
    public final Action exitAction = new AbstractAction("Exit") {

        public void actionPerformed(ActionEvent e) {
            application.exit();
        }
    };
    protected Action startServerAction = new AbstractAction() {

        {
            putValue(Action.NAME, "Start");
            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0));
        }

        public void actionPerformed(ActionEvent e) {
            application.startServer();
        }
    };
    protected Action stopServerAction = new AbstractAction() {

        {
            setEnabled(false);
            putValue(Action.NAME, "Stop");
            putValue(Action.MNEMONIC_KEY, KeyEvent.VK_F5 | KeyEvent.VK_CONTROL);
        }

        public void actionPerformed(ActionEvent e) {
            application.stopServer();
        }
    };
    protected Action showPreferencesAction = new AbstractAction("Options...") {

        public void actionPerformed(ActionEvent e) {
            application.showOptions();
        }
    };
    protected Action showAboutAction = new AbstractAction("About") {

        public void actionPerformed(ActionEvent e) {
            final AboutDialog aboutDialog = new AboutDialog(ServerFrame.this, true);
            aboutDialog.setVisible(true);
        }
    };
    protected Action allwaysOnTopAction = new AbstractAction() {

        private static final String PROP_CHECKED = "aatSelected";
        {
            putValue(Action.NAME, "Allways On Top");
            putValue(Action.SELECTED_KEY, false);
        }

        @Override
        public void putValue(String key, Object newValue) {
            if (Action.SELECTED_KEY.equals(key)) {
                setAlwaysOnTop((Boolean)newValue);
            }
            super.putValue(key, newValue);
        }

        public void actionPerformed(ActionEvent e) {
            AbstractButton button = (AbstractButton) e.getSource();
            setAlwaysOnTop(button.isSelected());
        }
    };

    protected Action showHelpAction = new AbstractAction("Online Help") {

        {
            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
        }

        public void actionPerformed(ActionEvent e) {
            try {
                System.getProperties().list(System.out);
                final BasicService bs = (BasicService) ServiceManager.lookup(
                        "javax.jnlp.BasicService");
                DbgError.assertNotNull("Can't find JNLP service", bs);
                final String address = System.getProperty("help.url");
                DbgError.assertNotNull("Can't find help.url system property. Deployment Error ?",
                        address);
                bs.showDocument(new URL(address));
            } catch (MalformedURLException ex) {
                DbgError.report(ex);
            } catch (UnavailableServiceException ex) {
                DbgError.report(ex);
            }
        }
    };

    abstract protected List<Image> createImages();

    protected List<Image> loadImages(String... resourceNames) {
        List<Image> resources = new ArrayList<Image>();
        for (final String resourceName : resourceNames) {
            try {
                resources.add(ImageIO.read(getClass().getResourceAsStream(
                        resourceName)));
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            } catch (IllegalArgumentException ex) {
                throw new RuntimeException(ex);
            }
        }
        return resources;
    }

    private Icon loadImage(final String resourceName) {
        try {
            return new ImageIcon(ImageIO.read(ServerFrame.class.getResourceAsStream(
                    resourceName)));
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    public ServerFrame(final Application<Message> application) throws HeadlessException {
        this.application = application;
        setIconImages(createImages());

        if (SystemTray.isSupported()) {
            tray = new ServerTraySupport(this, getIconImages().get(0));
        } else {
            tray = new ServerTrayVoid();
        }

        addWindowListener(new WindowAdapter() {

            @Override
            public void windowIconified(WindowEvent e) {
                tray.onFrameIconify();
            }
        });
        /**
         * Iconify with escape
         */
        getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                KeyStroke.getKeyStroke("ESCAPE"), "WINDOW_ICONIFIED");
        getRootPane().getActionMap().put("WINDOW_ICONIFIED", new AbstractAction() {

            public void actionPerformed(ActionEvent e) {
                if(System.getProperties().containsKey("noserver"))
                    application.exit();
                else
                    setState(JFrame.ICONIFIED);
            }
        });
    }

    public void onServerStatus(String text) {
        tray.onServerStatus(text);
        getStatusLablel().setText(text);
    }

    public void onServerStop(String message) {
        tray.onServerStop(message);
        getStatusLablel().setIcon(networkOffline);
        getStatusLablel().setText(message);
        startServerAction.setEnabled(true);
        stopServerAction.setEnabled(false);
    }

    public void onServerRecieved(Message message) {
        tray.onServerRecieved(message);
        getStatusLablel().setIcon(networkIdle);
        getStatusLablel().setText("Message recieved: " + message.toString());
    }

    public void onServerRecieve(String message) {
        tray.onServerRecieve(message);
        getStatusLablel().setIcon(networkRecieve);
    }

    public void onServerStart(String message) {
        tray.onServerStart(message);
        getStatusLablel().setIcon(networkIdle);
        getStatusLablel().setText("Server started: " + message);
        startServerAction.setEnabled(false);
        stopServerAction.setEnabled(true);
    }

    public void onServerCrash(String message) {
        tray.onServerCrash(message);
        getStatusLablel().setIcon(networkError);
        getStatusLablel().setText("Server crashed: " + message);
        startServerAction.setEnabled(true);
        stopServerAction.setEnabled(false);
    }

    void onOptionChange(Options options) {
    }
}
